package com.rw.tool.util.properties;

import com.fasterxml.jackson.core.type.TypeReference;
import com.rw.tool.util.json.JsonUtil;
import com.rw.tool.util.string.StringFormatter;
import com.rw.tool.util.string.StringUtil;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.util.Properties;

/**
 * 配置文件读取类
 */
public class PropertiesReader {
    private final Properties properties;

    /**
     * 读取配置文件
     *
     * @param path 配置文件路径
     */
    public PropertiesReader(String path, Charset charset) {
        URL resource = this.getClass().getClassLoader().getResource(path);
        if (resource == null) {
            final String ERROR_MSG = MessageFormat.format("Can not find the properties resource : {0}", path);
            throw new IllegalArgumentException(ERROR_MSG);
        }

        try (InputStream inputStream = resource.openStream();
             InputStreamReader reader = new InputStreamReader(inputStream, charset)) {
            properties = new Properties();
            properties.load(reader);
        } catch (IOException e) {
            throw new ReadPropertiesException(e);
        }
    }

    public PropertiesReader(String path, String charsetName) {
        this(path, Charset.forName(charsetName));
    }

    public PropertiesReader(String path) {
        this(path, StandardCharsets.UTF_8);
    }

    public String get(String key) {
        return properties.getProperty(key);
    }

    public byte getByte(String key) {
        return Byte.parseByte(get(key));
    }

    public boolean getBoolean(String key) {
        return Boolean.parseBoolean(get(key));
    }

    public char getChar(String key) {
        String value = get(key);
        if (!StringUtil.lengthIs(value, 1)) {
            String errorMessage = "\"{}\" Cannot cast to char!";
            throw new ReadPropertiesException(StringFormatter.format(errorMessage, value));
        }
        return value.charAt(0);
    }

    public short getShort(String key) {
        return Short.parseShort(get(key));
    }

    public int getInt(String key) {
        return Integer.parseInt(get(key));
    }

    public float getFloat(String key) {
        return Float.parseFloat(get(key));
    }

    public long getLong(String key) {
        return Long.parseLong(get(key));
    }

    public double getDouble(String key) {
        return Double.parseDouble(get(key));
    }

    /**
     * 读取配置文件中的值，如果这个值是Json格式
     * 则转为对应的类型
     *
     * @param key    键
     * @param tClass 转化的目标类型
     * @return 转化后的对象
     */
    public <T> T getObject(String key, Class<T> tClass) {
        return JsonUtil.toObject(properties.getProperty(key), tClass);
    }

    /**
     * 读取配置文件中的值，如果这个值是Json格式
     * 则转为对应的类型
     *
     * @param key           键
     * @param typeReference 转化的目标类型
     * @return 转化后的对象
     */
    public <T> T getObject(String key, TypeReference<T> typeReference) {
        return JsonUtil.toObject(properties.getProperty(key), typeReference);
    }

    /**
     * 读取配置文件中的值，如果目标值能够直接使用String转化
     * 则直接强转
     *
     * @param key    键
     * @param tClass 转化的目标类型
     * @return 转化后的对象
     */
    public <T> T getObjectConvert(String key, Class<T> tClass) {
        return JsonUtil.convertObj(properties.getProperty(key), tClass);
    }

    /**
     * 读取配置文件中的值，如果目标值能够直接使用String转化
     * 则直接强转
     *
     * @param key           键
     * @param typeReference 转化的目标类型
     * @return 转化后的对象
     */
    public <T> T getObjectConvert(String key, TypeReference<T> typeReference) {
        return JsonUtil.convertObj(properties.getProperty(key), typeReference);
    }
}
